package xyz.hubery.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import springfox.documentation.service.OAuth;
import xyz.hubery.config.IdAutoConfiguration;
import xyz.hubery.domain.User;
import xyz.hubery.domain.UserAuthAuditRecord;
import xyz.hubery.dto.UserDTO;
import xyz.hubery.feign.OAuth2FeignClient;
import xyz.hubery.geetest.GeetestLib;
import xyz.hubery.mapper.UserMapper;
import xyz.hubery.service.UserAuthAuditRecordService;
import xyz.hubery.service.UserService;
import xyz.hubery.vo.*;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserAuthAuditRecordService userAuthAuditRecordService;
    @Autowired
    private GeetestLib geetestLib;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @Override
    public List<UserDTO> getBasicUserInfo(List<Long> ids) {
        List<User> userList = list(new LambdaQueryWrapper<User>().in(User::getId, ids));
        // 转化为DTO对象
        if(CollectionUtils.isEmpty(userList)){
            return Collections.emptyList();
        }
        xyz.hubery.service.UserMapper mapper = xyz.hubery.service.UserMapper.userMapper;
        return mapper.toDTOs(userList);
    }

    @Override
    public boolean register(RegisterForm registerForm) {
        // 检验鸡眼
        registerForm.check(registerForm,geetestLib,redisTemplate);
        // 检查手机号是否被占用
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, registerForm.getMobile()));
        if(user!=null){
            throw new IllegalArgumentException("手机号被占用");
        }

        user = new User();
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        // 密码加密
        user.setPassword(passwordEncoder.encode(registerForm.getPassword()));
        // 设置手机号
        user.setMobile(registerForm.getMobile());
        user.setCountryCode(registerForm.getCountryCode());
        // 如果有邀请码，设置
        if(!StringUtils.isEmpty(registerForm.getInvitionCode())) {
            // 根据邀请码查询用户
            User inviteUser = getOne(new LambdaQueryWrapper<User>().eq(User::getInviteCode, registerForm.getInvitionCode()));
            if(inviteUser!=null){
                user.setDirectInviteid(inviteUser.getId().toString());
            }
        }
        // 设置状态
        user.setStatus((byte)1);
        return this.save(user);
    }

    /**
     * 修改用户的审核状态
     *
     * @param id
     * @param authStatus
     * @param authCode
     */
    @Override
    @Transactional
    public void updateUserAuthStatus(Long id, Byte authStatus, Long authCode, String remark) {
        log.info("开始修改用户的审核状态,当前用户{},用户的审核状态{},图片的唯一 code{}", id, authStatus, authCode);
        User user = getById(id);
        if (user != null) {// user.setAuthStatus(authStatus); // 认证的状态
            user.setReviewsStatus(authStatus.intValue()); // 审核的状态
            updateById(user); // 修改用户的状态
        }
        UserAuthAuditRecord userAuthAuditRecord = new UserAuthAuditRecord();
        userAuthAuditRecord.setUserId(id);
        userAuthAuditRecord.setStatus(authStatus);
        userAuthAuditRecord.setAuthCode(authCode);
        String usrStr =
                SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        userAuthAuditRecord.setAuditUserId(Long.valueOf(usrStr)); // 审核人的 ID
        userAuthAuditRecord.setAuditUserName("---------------------------");// 审核人的名称 --> 远程调用 admin-service ,没有事务
        userAuthAuditRecord.setRemark(remark);
        userAuthAuditRecordService.save(userAuthAuditRecord);
    }

    @Override
    public boolean authAccount(Long userId, IdentifyForm identifyForm) {
        // 根据用户 ID 查询用户信息
        User user = getById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        if (!user.getAuthStatus().equals((byte) 0)) {
            throw new IllegalArgumentException("用户已认证");
        }
        // 极验验证
        identifyForm.check(identifyForm, geetestLib, redisTemplate);
        // 认证
        boolean checked = IdAutoConfiguration.check(identifyForm.getRealName(), identifyForm.getIdCard());

        if (!checked) {
            throw new IllegalArgumentException("实名认证失败");
        }

        // 认证成功，封装用户信息
        user.setAuthStatus((byte) 1);
        user.setRealName(identifyForm.getRealName());
        user.setIdCard(identifyForm.getIdCard());
        user.setIdCardType(identifyForm.getIdCardType());
        user.setAuthtime(new Date());
        // 更新用户信息
        return updateById(user);
    }

    @Override
    public User getById(Serializable id) {
        User user = super.getById(id);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        Byte seniorAuthStatus = null; // 0审核中、1通过、2拒绝、3未填写
        String seniorAuthDesc = "";
        // 获取用户审核状态
        Integer reviewsStatus = user.getReviewsStatus();  //1通过,2拒绝,0,待审核
        if (reviewsStatus == null) { // 未填写
            seniorAuthStatus = 3;
            seniorAuthDesc = "未填写";
        } else {
            switch (reviewsStatus) {
                case 0: // 待审核
                    seniorAuthStatus = 0;
                    seniorAuthDesc = "审核中";
                    break;
                case 1: // 通过
                    seniorAuthStatus = 1;
                    seniorAuthDesc = "已通过";
                    break;
                case 2: // 拒绝
                    seniorAuthStatus = 2;
                    seniorAuthDesc = "已拒绝";
                    // 查询拒绝理由
                    // 查询用户的审核记录
                    List<UserAuthAuditRecord> records = userAuthAuditRecordService.findByUserId((Long) id);
                    // 获取首条记录
                    if (!CollectionUtils.isEmpty(records)) {
                        UserAuthAuditRecord record = records.get(0);
                        seniorAuthDesc = record.getRemark();
                    }
                    break;
            }
        }
        user.setSeniorAuthStatus(seniorAuthStatus);
        user.setSeniorAuthDesc(seniorAuthDesc);
        return user;
    }

    @Override
    public boolean checkNewTelAndSend(String mobile, String countryCode) {
        // 根据手机号查询用户
        User newUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile));
        if (newUser != null) {
            return false;
        }
        // 发送短信
        redisTemplate.opsForValue().set("SMS:" + mobile, "123456", 5, TimeUnit.MINUTES);
        return true;
    }

    @Override
    public boolean checkPhoneAndCode(Long userId, UpdatePhoneRequest phoneRequest) {
        // 查询用户旧手机号
        User user = getById(userId);
        String oldPhone = user.getMobile();
        // 比对旧手机号的验证码
        String oldCodeCache = redisTemplate.opsForValue().get("SMS:" + oldPhone);
        if (oldCodeCache != null && oldCodeCache.equals(phoneRequest.getOldValidateCode())) { // 校验成功
            // 比对新手机号的验证码
            String newCodeCache = redisTemplate.opsForValue().get("SMS:" + phoneRequest.getNewMobilePhone());
            if (newCodeCache != null && newCodeCache.equals(phoneRequest.getValidateCode())) {
                // 校验成功，修改手机号
                user.setMobile(phoneRequest.getNewMobilePhone());
                // 删除缓存
                redisTemplate.delete("SMS:" + oldPhone);
                redisTemplate.delete("SMS:" + phoneRequest.getNewMobilePhone());
                return this.updateById(user);
            }
        }
        return false;
    }


    @Override
    public boolean setPassword(SetPasswordRequest passwordRequest) {
        // 根据手机号查询用户
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, passwordRequest.getMobile()));
        if(user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        // 鸡眼校验
        passwordRequest.check(passwordRequest, geetestLib, redisTemplate);
        // 校验验证码
        boolean checkPhoneCode = checkPhoneCode(passwordRequest.getMobile(), passwordRequest.getValidateCode());
        if(!checkPhoneCode) {
            throw new IllegalArgumentException("验证码错误");
        }
        // 跟新密码
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        user.setPassword(passwordEncoder.encode(passwordRequest.getPassword()));
        user.setCountryCode(passwordRequest.getCountryCode());
        return updateById(user);
    }

    @Override
    public List<User> invitesList(Long userId) {
       return this.list(new LambdaQueryWrapper<User>().eq(User::getDirectInviteid,userId));
    }

    @Override
    public boolean updatePayPassword(Long userId, UpdatePayPasswordRequest passwordRequest) {
        // 查询用户
        User user = getById(userId);
        if(user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        // 校验验证码
        boolean checkPhoneCode = checkPhoneCode(user.getMobile(), passwordRequest.getValidateCode());
        if(!checkPhoneCode) {
            throw new IllegalArgumentException("验证码错误");
        }
        // 校验旧密码
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if(passwordEncoder.matches(passwordRequest.getOldpassword(), user.getPaypassword())) {
            // 加密交易密码
            user.setPaypassword(passwordEncoder.encode(passwordRequest.getNewpassword()));
            return updateById(user);
        }
        return false;
    }

    @Override
    public boolean setPayPassword(Long userId, ResetPayPasswordRequest passwordRequest) {
        // 查询用户
        User user = getById(userId);
        if(user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        // 校验验证码
        boolean checkPhoneCode = checkPhoneCode(user.getMobile(), passwordRequest.getValidateCode());
        if(!checkPhoneCode) {
            throw new IllegalArgumentException("验证码错误");
        }
        // 加密交易密码
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        user.setPaypassword(passwordEncoder.encode(passwordRequest.getPayPassword()));
        user.setPaypassSetting(true);
        return updateById(user);
    }

    @Override
    public boolean updateLoginPassword(Long userId, UpdateLoginPasswordRequest passwordRequest) {
        // 根据用户id查询用户
        User user = getById(userId);
        // 比对验证码
        boolean checked = checkPhoneCode(user.getMobile(), passwordRequest.getValidateCode());
        if (!checked) { // 验证码错误
            return false;
        }
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        // 比对旧密码
        String oldpassword = passwordRequest.getOldpassword();
        String password1 = user.getPassword();
        boolean matches = passwordEncoder.matches(passwordRequest.getOldpassword(), user.getPassword());
        if (!matches) { // 旧密码错误
            return false;
        }
        // 更新密码
        String password = passwordEncoder.encode(passwordRequest.getNewpassword());
        user.setPassword(password);
        return this.updateById(user);
    }

    /**
     * 校验手机号验证码是否正确
     *
     * @return
     */
    private boolean checkPhoneCode(String mobile, String code) {
        // 根据手机号查询验证码缓存
        String codeCache = redisTemplate.opsForValue().get("SMS:" + mobile);
        // 比对
        if (codeCache != null && codeCache.equals(code)) {
            // 删除验证码
            redisTemplate.delete("SMS:" + mobile);
            return true;
        }
        return false;
    }
}
